#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

// int main()
// {
//   printf("testexec ... begin!\n");
//   pid_t id = fork();
  
//   if(id == 0)
//   {
//     // 传入的环境变量和参数都只能通过字符串数组的形式给出，而且这个字符串数组的最后一个参数必须是NULL
//     // exec族函数是在创建子进程之后，可以在子进程中执行新的程序，这个程序可以是用其他语言编写的程序
//     下面这段程序中execl函数实际上实现了程序替换，
//     将原来进程中的代码和数据 用 execl这个函数中所找到的可执行程序和数据进行替换，
//     注意：m1. 这里不会讲pcb，地址空间，页表进行替换，只会把页表中的指向关系进行替换
//     m2. 如果替换成功，则不会执行printf("testexec ... end!\n"); 这句话
//     m3. 如果替换失败，则将执行这句话，失败的原因可能 是在磁盘上找不到execl这个函数的第一个参数
//     m4. 这里的替换不仅会把execl中的对应数据通过写时拷贝写到子进程的对应的物理内存中，
//     也会把execl中找到的代码通过拷贝写到子进程对应的物理内存中
//     // execl函数会找到当前目录下的test.py文件，生成这个文件的可执行文件之后
//     // 此时在对testexe.c这个文件进行编译，要执行编译后的可执行文件，
//     // 就是将testexe.c的main函数中的
//     // execl("/usr/bin/python3", "python3", "test.py", NULL);
//     //这一行后的代码替换成test.py对应的可执行代码
//     // execl("/usr/bin/python3", "python3", "test.py", NULL);
//     // sleep(2);
//     char* const argv[] = 
//     {
//      (char*)"ls",
//      (char*)"-l",
//      (char*)"-a",
//      (char*)"--color",
//      NULL
//     };
//     // execv("/usr/bin/", argv);
//     execvp("ls", argv);
//     // execlp("top", "top", NULL);
//     exit(1);
//   }
//   int status = 0;
//   pid_t rid = waitpid(id, &status, 0);
//   if(rid > 0)
//   {
//     printf("father wait success, child exit code: %d\n", WEXITSTATUS(status));
//   }
//
//   printf("testexec ... end!\n");
//
//   return  0;
// }

// int main()
// {
//     char* const argv[] = 
//     {
//       (char*)"myprog",
//       (char*)"-a",
//       (char*)"-b",
//       NULL 
//     };

//     char* const envp[] = 
//     {
//       (char*)"H=1",
//       (char*)"E=1",
//       NULL 
//     };

//     extern char** environ;
//     printf("child pid: %d\n", getpid());
//     usleep(1000);

//     // 这里编写了一个myprog.cc程序，这个程序的main 函数中传入了参数列表 和 环境变量列表
//     // myprog.cc 中main 函数实现的是将参数 和 环境变量进行打印
//     // 这里的 execvpe 就是将testexe.c中定义的参数 和 环境列表传给myprog.cc，
//     // 并且在进程中将后面所有的执行语句都替换成 ./myprog
//     execvpe("./myprog", argv, environ);

//   return 0;
// }

int main()
{
    // execl函数会找到当前目录下的test.py文件，生成这个文件的可执行文件之后
    // 此时在对testexe.c这个文件进行编译，要执行编译后的可执行文件，
    // 就是将testexe.c的main函数中的
  printf("testexec ... begin!\n");
  pid_t id = fork();

  if(id == 0)
  {
    // execl函数需要3类参数，这里要通过execl函数执行Python3，必须通过下述方式
    // 第一：标识符所存储的路径
    // 第二：标识符
    // 第三：标识符所需要的参数
    execl("/usr/bin/python3", "python3", "test.py", NULL);
    //这一行后的代码替换成test.py对应的可执行代码
    execl("/usr/bin/python3", "python3", "test.py", NULL);
    sleep(2);
  }
  int status = 0;
  pid_t rid = waitpid(id, &status, 0);
  if(rid > 0)
  {
    printf("father wait success, child exit code: %d\n", WEXITSTATUS(status));
  }

  printf("testexec ... end!\n");

  return  0;
}
